package com.study.springbootsecurity.config.redis;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;

/**
 * FastJSON 实现的 Redis 序列化器，用于将对象序列化为字节数组和反序列化为对象
 * 支持泛型类型，可通过构造函数指定具体类型
 *
 * @param <T> 序列化/反序列化对象的类型
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

    /** 默认字符集，用于序列化和反序列化 */
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    /** 序列化/反序列化对象的类型 */
    private final Class<T> targetClass;

    /**
     * 静态初始化块，启用 FastJSON 的自动类型支持
     * 这允许在序列化时存储对象类型信息，以便在反序列化时正确还原对象类型
     */
    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }

    /**
     * 构造函数，初始化时需指定目标类型
     *
     * @param targetClass 目标类型的 Class 对象
     */
    public FastJsonRedisSerializer(Class<T> targetClass) {
        super();
        this.targetClass = targetClass;
    }

    /**
     * 将对象序列化为字节数组
     *
     * @param object 待序列化的对象
     * @return 序列化后的字节数组，若对象为 null 则返回空字节数组
     * @throws SerializationException 序列化过程中发生错误时抛出
     */
    @Override
    public byte[] serialize(T object) throws SerializationException {
        // 处理 null 对象，避免 NPE
        if (object == null) {
            return new byte[0];
        }

        try {
            // 使用 FastJSON 将对象转换为 JSON 字符串，并添加类型信息
            // SerializerFeature.WriteClassName 会在 JSON 中包含对象的类信息
            String jsonString = JSON.toJSONString(object, SerializerFeature.WriteClassName);
            return jsonString.getBytes(DEFAULT_CHARSET);
        } catch (Exception e) {
            // 包装异常为 Spring 的 SerializationException
            throw new SerializationException("FastJSON 序列化失败", e);
        }
    }

    /**
     * 将字节数组反序列化为对象
     *
     * @param bytes 待反序列化的字节数组
     * @return 反序列化后的对象，若字节数组为空则返回 null
     * @throws SerializationException 反序列化过程中发生错误时抛出
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        // 处理空字节数组，避免无效处理
        if (bytes == null || bytes.length == 0) {
            return null;
        }

        try {
            // 将字节数组转换为字符串
            String jsonString = new String(bytes, DEFAULT_CHARSET);
            // 使用 FastJSON 解析 JSON 字符串为指定类型的对象
            // 利用之前存储的类型信息正确还原对象类型
            return JSON.parseObject(jsonString, targetClass);
        } catch (Exception e) {
            // 包装异常为 Spring 的 SerializationException
            throw new SerializationException("FastJSON 反序列化失败", e);
        }
    }

    /**
     * 获取 Java 类型信息，用于复杂类型的序列化/反序列化
     * 该方法目前未被使用，但保留作为扩展点
     *
     * @param clazz 类对象
     * @return JavaType 对象，表示具体的泛型类型
     */
    protected JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}
